#ifndef __FORCE_H__
#define __FORCE_H__

#include <vector>
#include "vec.h"
#include "particle.h"

////////////
// Forces //
////////////

// Base class used to represent a general force
class Force {
public:
	virtual void accountForces() = 0; // accounts for forces on particles

};

// Abstract subclass used to represent particles which are typically global (or close to that)
class GlobalForce : public Force {
public:

	// Makes given particle affected by our force
	void AddParticle(Particle *p);

	// adds everything in the particle list to the affected particles. Note that this does NOT bind the 2 lists together
	void AddParticles(vector<Particle*>& particleList); 

	virtual void accountForces() = 0;
protected:

	// Particles which are affected by our force
	vector<Particle*> affectedParticles;
};

// Constant force (NOT like gravity). Does NOT have to affect ALL particles!
// This force is constant REGARDLESS of the properties of the object!
// So gravity is NOT one of these!, but things like "wind" are!
class ConstantForce : public GlobalForce {

public:
	ConstantForce(Vec3d constForce);
	void accountForces();

protected:
	Vec3d _constForce;

};

// Randmon force (Randmon direction, constant magnitude). 
// Only exist for certain amount of time while for the time being the force was constant.
class RandomForce : public ConstantForce {
public:
	RandomForce(double magnitude, double timeToLive, double step);
	void accountForces();
	double getTimeToLive() {return _timeToLive;};
	void decayForceLife(double step);

private:
	double _timeToLive;
	double _step;

};


// Field force - dependant on the properties of the particle AND the location
// Eg. non-uniform g-fields etc
class FieldForce : public GlobalForce {
public:
	virtual void accountForces() = 0;
};

// Uniform graviational field
class ConstantGravitationalField : public FieldForce {
public:
	ConstantGravitationalField(Vec3d gFieldStrength);
	virtual void accountForces();
private: 
	Vec3d _gFieldStrength;
};

// Viscous drag force, f = -kd * v, where kd is the coeffecient of drag
class DragForce : public GlobalForce {

public:
	DragForce(double kd);
	void accountForces();

private:
	double _kd;

};

// Pair force
typedef pair<Particle*, Particle*> ParticlePair;
class PairForce : public Force {
public:
	virtual void accountForces() = 0;
	virtual void addParticlePair(Particle* p1, Particle* p2); // assume order of particles will not make a difference
protected:
	vector<ParticlePair> pairs;
};

// Spring force
class SpringForce : public PairForce {
public:
	SpringForce(double ks, double kd); // take spring constant
	void addParticlePair(Particle* p1, Particle* p2); // we will have to care about the starting displacements as well
	void accountForces();
protected:
	vector<double> restLengths;
	double _ks;
	double _kd;
};

#endif